﻿#include "Active/ActiveCharacterMgr.h"
#include "base/core/guid.h"
#include "base/core/os/time.h"
#include "Common/LoginDefine.h"
#include "Common/Utility/ServerTime.h"
#include "ProtoBuffer/AllProtocol.h"
#include "CenterService.h"
#include "Cache/OfflineCharacterDataMgr.h"
#include "CenterService.h"
#include "Common/Event/Event.h"
#ifdef _MSC_VER
#pragma warning(disable:4100)
#endif

namespace 
{
	static const uint32_t s_onlineActivePoolSize = 100;
}

ActiveCharacterMgr::ActiveCharacterMgr()
	: ManualSingleton<ActiveCharacterMgr>()
	, m_pActiveCharacterPool(nullptr)
	, m_OnlineCharacterMap()
{}

ActiveCharacterMgr::~ActiveCharacterMgr()
{}

bool ActiveCharacterMgr::Init()
{
    bool result = false;

	m_pActiveCharacterPool = new ObjectPool<ActiveCharacter>(s_onlineActivePoolSize, false);
	MMOLOG_ASSERT_EXIT(m_pActiveCharacterPool != nullptr);
	//每天0点检查活跃玩家数据
	//g_GetTimerAxis()->SetFixTimer((uint32_t)EACTIVE_MGR::TIMER_ID_CHECK_ACTIVE_DATA, 0, 1, this);

    result = true;
Exit0:
    return result;
}

bool ActiveCharacterMgr::UnInit()
{
	g_GetTimerAxis()->KillAllFixTimer(this);
	g_GetTimerAxis()->KillAllTimer(this);

	_ClearAllActiveCharacter();

	MMO_DELETE(m_pActiveCharacterPool);

    return true;
}

bool ActiveCharacterMgr::Update(uint64_t tick)
{
    return true;
}

void ActiveCharacterMgr::OnTimer(uint32_t nTimerID)
{
	switch (nTimerID)
	{
	case (uint32_t)EACTIVE_MGR::TIMER_ID_CHECK_ACTIVE_DATA:
		{
			CheckActiveCharacter();
		}
		break;
	default:
		break;
	}
}

//检查所有活跃数据
void ActiveCharacterMgr::CheckActiveCharacter()
{
	uint64_t nCurTime = g_GetGlobalServerTime()->UnixSec();
	LogDebugFmtPrint("[center] every day zero clock check active character data...time:%lu ",nCurTime);
	ACTIVE_CHARACTER_MAP::iterator iter = m_ActiveCharacterMap.begin();
	while (iter != m_ActiveCharacterMap.end())
	{
		ActiveCharacter *pActive = iter->second;
		if (nullptr != pActive)
		{
			OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(pActive->GetCharID());
			if (nullptr != pOffline)
			{
				uint64_t nLastLogout = pOffline->GetLastLogout();
				if (1 == nLastLogout
					|| ((nCurTime - nLastLogout) < (uint64_t)EACTIVE_MGR::MAX_ACTIVE_CHARACTER_SAVE_TIME)
					|| pActive->GetArenaFlag()
					)
				{
					//角色在线，具体上次登出时间小于7天，在竞技场排名中
					++iter;
					continue;
				}
			}

			
			//
			FreeActiveCharacter(pActive);
			iter = m_ActiveCharacterMap.erase(iter);
			continue;
		}
		++iter;
	}
}

bool ActiveCharacterMgr::_ClearAllActiveCharacter()
{
	m_OnlineCharacterMap.clear();

	ACTIVE_CHARACTER_MAP::iterator iter = m_ActiveCharacterMap.begin();
	for (; iter != m_ActiveCharacterMap.end(); ++iter)
	{
		ActiveCharacter *pOnline = iter->second;
		if (nullptr != pOnline)
		{
			FreeActiveCharacter(pOnline);
		}
	}
	
	m_ActiveCharacterMap.clear();

	return true;
}

//增加观察者
bool ActiveCharacterMgr::AddCharacterObserver(ICharacterObserver *pCharacterObserver)
{
	if (nullptr == pCharacterObserver)
	{
		return false;
	}
	m_CharacterObserverList.push_back(pCharacterObserver);
	return true;
}

//移除观察者
bool ActiveCharacterMgr::RemoveCharacterObserver(ICharacterObserver *pCharacterObserver)
{
	if (nullptr == pCharacterObserver)
	{
		return false;
	}
	m_CharacterObserverList.remove(pCharacterObserver);
	return true;
}

//角色登录
bool ActiveCharacterMgr::OnCharacterLogin(CenterLoginLogicRsp &enter,uint32_t channelId)
{
	CharIDType charID = enter.cid();
	const CenterCharacterInfo &charInfoProto = enter.centercharacter();
	const CharacterDBSimpleInfo &simple = charInfoProto.charsimpleinfo();

	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterLogin can not find offline data , charid:%lu ",charID);
		return false;
	}
	//
	bool bActiveFlag = true;
	ActiveCharacter *pOnline = GetActiveCharacter(charID);
	if (nullptr == pOnline)
	{
		bActiveFlag = false;
		pOnline = MakeActiveCharacter();
		if (nullptr == pOnline)
		{
			MMOLOG_FMT_ERROR("[center] nullptr == pOnline MakeActiveCharacter , charid:%llu ", charID);
			return false;
		}
	}
	//更新离线数据
	pOffline->SetFight(simple.fightpower());
	pOffline->SetLevel((int16_t)simple.level());
	pOffline->SetProf((uint8_t)simple.prof());
	pOffline->SetSex((uint8_t)simple.sex());
	pOffline->SetRace(simple.race());
	pOffline->SetCampID((int8_t)simple.camp());
	pOffline->SetOfficial(simple.official());
	pOffline->SetKnight(simple.knight());
	pOffline->SetContribute(simple.contribute());
	pOffline->SetContriCoin(simple.contricoin());
	pOffline->SetPrestige(simple.prestige());
	pOffline->SetKillCount(simple.killers());
	pOffline->SetCharm(simple.charm());
	pOffline->SetHisPrestige(simple.hisprestige());
	pOffline->SetLastLogout(1);		//设置角色在线
	pOffline->SetChannelId(channelId);
	//
	pOnline->Init(charID);
	pOnline->SetDisconnectFlag(0);	//设置没有断开连接
	pOnline->SetMapID(charInfoProto.map_id());
	pOnline->SetSceneID(charInfoProto.scene_id());
	CharFacadeProto newproto(pOffline->GetFacade());
	//装备
	int32_t nEquipSize = charInfoProto.equip_size();
	for (int32_t i = 0; i < nEquipSize; ++i)
	{
		const ItemProtoInfo &proto = charInfoProto.equip(i);
		pOnline->SetEquipInfo(proto.index(), &proto);
	}
	//外观
	pOffline->SetFacade(simple.facade());
	//详细属性
	if (charInfoProto.has_attr())
	{
		const CharacterDBAttrDetailInfo &attr = charInfoProto.attr();
		pOnline->SetDetailAttr(attr);
		pOnline->SetLastAttrUpdate(C_HP, attr.cur_hp());
		pOnline->SetLastAttrUpdate(C_MAX_HP, attr.max_hp());
		pOnline->SetLastAttrUpdate(C_LEVEL, simple.level());
	}

	if (!bActiveFlag)
	{
		m_ActiveCharacterMap[pOnline->GetCharID()] = pOnline;
	}

	m_OnlineCharacterMap[pOnline->GetCharID()] = pOnline;

	//通知观察者角色上线了
	CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
	for (; iter != m_CharacterObserverList.end(); ++iter)
	{
		ICharacterObserver *pObserver = (*iter);
		if (nullptr != pObserver)
		{
			pObserver->onCharacterLogin(pOnline);
		}
	}

	LogDebugFmtPrint("[center] OnCharacterLogin  account:%u,charID:%lu,fight:%d,lev:%d  ", pOffline->GetUid(), charID, pOffline->GetFight(), pOffline->GetLevel());

	return true;
}

//角色下线
bool ActiveCharacterMgr::OnCharacterLogout(CharIDType charID)
{
	//下线逻辑，暂时不要回收在线玩家对象，因为后面观察者回调还需要用到
	if (charID <= 0)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterLogout charID <= 0 ,charID:%lu ",charID );
		return false;
	}
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterLogout can not find offline data , charid:%llu ", charID);
		return false;
	}

	//设置角色登出时间
	uint64_t nCurTime = g_GetGlobalServerTime()->UnixSec();
	pOffline->SetLastLogout(nCurTime);

	ActiveCharacter *pOnline = GetOnlineCharacter(charID);
	if (nullptr == pOnline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterLogout can not find online character data , charid:%llu ,account:%d ", charID, pOffline->GetUid());
		return false;
	}

	//通知观察者角色下线了
	if (nullptr != pOnline)
	{
		CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
		for (; iter != m_CharacterObserverList.end(); ++iter)
		{
			ICharacterObserver *pObserver = (*iter);
			if (nullptr != pObserver)
			{
				pObserver->onCharacterLogout(pOnline);
			}
		}
	}

	//这里可以回收在线玩家对象
	m_OnlineCharacterMap.erase(charID);


	LogDebugFmtPrint("[center] OnCharacterLogout  account:%u ,charID:%llu ",pOffline->GetUid(), charID);

	return true;
}
//删除角色
bool ActiveCharacterMgr::OnCharacterDel(CharIDType charID)
{
	if (charID <= 0)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterDel charID <= 0 ,charID:%lu ", charID);
		return false;
	}
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterDel can not find offline data , charid:%lu ", charID);
		return false;
	}
	//通知观察者删除角色
	CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
	for (; iter != m_CharacterObserverList.end(); ++iter)
	{
		ICharacterObserver *pObserver = (*iter);
		if (nullptr != pObserver)
		{
			pObserver->onCharacterDel(pOffline);
		}
	}

	// 如果在活跃数据中，需要删除
	ActiveCharacter *pActiveChar = GetActiveCharacter(charID);
	if (nullptr != pActiveChar)
	{
		//从活跃map中删除
		m_ActiveCharacterMap.erase(charID);
		//从在线列表中删除
		m_OnlineCharacterMap.erase(charID);
		//回收
		FreeActiveCharacter(pActiveChar);
	}
	//离线数据删除放到最后
	g_GetOfflineCharacterDataMgr()->DelOfflineCharacter(pOffline);

	return true;
}
//角色更新
void ActiveCharacterMgr::OnCharacterUpdate(LogicToCenterCharSync &charSync)
{
	//更新逻辑
	CharIDType charID = charSync.charid();
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterUpdate can not find character offline data , charid:%lu ",charID);
		return;
	}
	//这里更新离线数据
	pOffline->AttrUpdate(charSync.attrlist());

	ActiveCharacter *pOnline = GetOnlineCharacter(charID);
	if (nullptr == pOnline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterUpdate can not find character online data , charid:%lu ", charID);
		return;
	}
	//设置同步信息
	pOnline->SetCharSyncProto(charSync, pOffline);

	//通知观察者角色更新
	if (nullptr != pOnline)
	{
		CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
		for (; iter != m_CharacterObserverList.end(); ++iter)
		{
			ICharacterObserver *pObserver = (*iter);
			if (nullptr != pObserver)
			{
				pObserver->onCharacterUpdate(pOnline);
			}
		}
	}
}

//角色外观更新
void ActiveCharacterMgr::OnCharacterFacadeUpdate(LogicToCenterCharFacadeSync &facade)
{
	CharIDType charID = facade.charid();
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] OnCharacterFacadeUpdate can not find character offline data , charid:%lu ", charID);
		return;
	}
	pOffline->SetFacade(facade.facade());
	ActiveCharacter *pOnline = GetOnlineCharacter(charID);
	if (nullptr == pOnline)
	{
		LogErrFmtPrint("[center] ActiveCharacterMgr::OnCharacterFacadeUpdate can not find online char data ,charid:%lu ", charID);
		return;
	}
	//通知观察者外观改变
	CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
	for (; iter != m_CharacterObserverList.end(); ++iter)
	{
		ICharacterObserver *pObserver = (*iter);
		if (nullptr != pObserver)
		{
			pObserver->onCharacterFacadeUpdate(pOffline);
		}
	}
}

//角色切换场景
void ActiveCharacterMgr::OnCharacterChangeScene(CharIDType cid, uint32_t sceneId, uint32_t mapId, Point3<float> pos)
{
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(cid);
	if (nullptr == pOffline)
	{
		//MMOLOG_FMT_ERROR("[center] OnCharacterChangeScene can not find character offline data , charid:%u ", cid);
		return;
	}
	ActiveCharacter *pOnline = GetOnlineCharacter(cid);
	if (nullptr == pOnline)
	{
		//MMOLOG_FMT_ERROR("[center] OnCharacterChangeScene can not find character online data , charid:%u ", cid);
		return;
	}
	pOnline->SetSceneID(sceneId);
	pOnline->SetMapID(mapId);
	pOnline->SetPos(pos);

	//通知观察者切换场景
	CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
	for (; iter != m_CharacterObserverList.end(); ++iter)
	{
		ICharacterObserver *pObserver = (*iter);
		if (nullptr != pObserver)
		{
			pObserver->onCharacterSwitchScene(pOnline);
		}
	}
}

//角色断开连接
void ActiveCharacterMgr::OnCharacterDisconnect(CharIDType charID)
{
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		//MMOLOG_FMT_ERROR("[center] OnCharacterChangeScene can not find character offline data , charid:%u ", charID);
		return;
	}
	ActiveCharacter *pOnline = GetOnlineCharacter(charID);
	if (nullptr == pOnline)
	{
		//MMOLOG_FMT_ERROR("[center] OnCharacterChangeScene can not find character online data , charid:%u ", charID);
		return;
	}
	pOnline->SetDisconnectFlag(1); //设置断开连接

	//通知观察者切换场景
	CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
	for (; iter != m_CharacterObserverList.end(); ++iter)
	{
		ICharacterObserver *pObserver = (*iter);
		if (nullptr != pObserver)
		{
			pObserver->onCharacterDisconnect(pOnline);
		}
	}
}

//角色重连
void ActiveCharacterMgr::onCharacterReconnect(CharIDType charID)
{
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		//MMOLOG_FMT_ERROR("[center] OnCharacterChangeScene can not find character offline data , charid:%u ", charID);
		return;
	}
	ActiveCharacter *pOnline = GetOnlineCharacter(charID);
	if (nullptr == pOnline)
	{
		//MMOLOG_FMT_ERROR("[center] OnCharacterChangeScene can not find character online data , charid:%u ", charID);
		return;
	}

	pOnline->SetDisconnectFlag(0); //设置断开连接

	//通知观察者切换场景
	CHARACTER_OBSERVER_LIST::iterator iter = m_CharacterObserverList.begin();
	for (; iter != m_CharacterObserverList.end(); ++iter)
	{
		ICharacterObserver *pObserver = (*iter);
		if (nullptr != pObserver)
		{
			pObserver->onCharacterReconnect(pOnline);
		}
	}
}

//获取在线角色
ActiveCharacter* ActiveCharacterMgr::GetOnlineCharacter(CharIDType id)
{
	ONLINE_CHARACTER_MAP::iterator iter = m_OnlineCharacterMap.find(id);
	if (iter != m_OnlineCharacterMap.end())
	{
		return iter->second;
	}
	return nullptr;
}

//获取活跃角色
ActiveCharacter* ActiveCharacterMgr::GetActiveCharacter(CharIDType id)
{
	ACTIVE_CHARACTER_MAP::iterator iter = m_ActiveCharacterMap.find(id);
	return (iter != m_ActiveCharacterMap.end()) ? iter->second : nullptr;
}
//获取一个活跃角色对象
ActiveCharacter* ActiveCharacterMgr::MakeActiveCharacter()
{
	MMO_ASSERT(m_pActiveCharacterPool != nullptr);
	return m_pActiveCharacterPool->MallocObj();
}
//添加一个活跃玩家数据
bool  ActiveCharacterMgr::AddActiveCharacter(const ActiveCharacterDBInfo &info)
{
	CharIDType charID = info.charid();
	ActiveCharacter *pActive = GetActiveCharacter(charID);
	if (nullptr != pActive)
	{
		MMOLOG_FMT_ERROR("[center] AddActiveCharacter...active character already in memory , charid:%llu ", charID);
		return false;
	}
	OfflineCharacterData *pOffline = g_GetOfflineCharacterDataMgr()->GetOfflineCharacter(charID);
	if (nullptr == pOffline)
	{
		MMOLOG_FMT_ERROR("[center] AddActiveCharacter can not find offline data , charid:%llu ", charID);
		return false;
	}
	pActive = MakeActiveCharacter();
	if (nullptr == pActive)
	{
		MMOLOG_FMT_ERROR("[center] AddActiveCharacter...MakeActiveCharacter return nullptr , charid:%llu ", charID);
		return false;
	}
	const CharacterDBBaseInfo &base = info.basedata();
	const CharacterDBEquipData &equip = info.equipdata();
	const CharacterDBExtendData &extra = info.extenddata();

	//
	pActive->Init(charID);
	pActive->SetMapID(base.enter_map_id());
	pActive->SetSceneID(base.enter_scene_id());
	//装备
	int32_t nEquipSize = equip.equip_size();
	for (int32_t i = 0; i < nEquipSize; ++i)
	{
		const ItemProtoInfo &proto = equip.equip(i);
		pActive->SetEquipInfo(proto.index(), &proto);
	}
	//详细属性
	if (extra.has_attr_detail())
	{
		const CharacterDBAttrDetailInfo &attr = extra.attr_detail();
		pActive->SetDetailAttr(attr);
	}
	//
	m_ActiveCharacterMap[pActive->GetCharID()] = pActive;

	return true;
}
//回收一个活跃角色对象
bool ActiveCharacterMgr::FreeActiveCharacter(ActiveCharacter* activeCharacter)
{
	if (nullptr == m_pActiveCharacterPool || nullptr == activeCharacter)
	{
		return false;
	}
	m_pActiveCharacterPool->FreeObj(activeCharacter);

	return true;
}
//获取在线人数
uint32_t ActiveCharacterMgr::GetOnlineNum()
{
	return (uint32_t)m_OnlineCharacterMap.size();
}

ActiveCharacterMgr::ONLINE_CHARACTER_MAP& ActiveCharacterMgr::GetOnlineCharacterMap()
{
	return m_OnlineCharacterMap;
}